package model.symbol;

import java.util.ArrayList;

/**
 * This class is specific to assembly language instruction mnemonics.
 *
 * @author Neil Dickson
 */
public class Mnemonic extends Keyword {
	private ArrayList<Object[]>	operandTypes16;
	private ArrayList<Object[]>	operandTypes32;
	private ArrayList<Object[]>	operandTypes64;
	private	int					minNumOperands;
	private	int					maxNumOperands;
	private ArrayList<short[]>	encodings16;
	private ArrayList<short[]>	encodings32;
	private ArrayList<short[]>	encodings64;
	private ArrayList<String>	descriptions16;
	private ArrayList<String>	descriptions32;
	private ArrayList<String>	descriptions64;
	private ArrayList<String[]>	categories16;
	private ArrayList<String[]>	categories32;
	private ArrayList<String[]>	categories64;

	public Mnemonic(String mnemonic, String description) {
		super(mnemonic, description);
		operandTypes16 = new ArrayList<Object[]>();
		operandTypes32 = new ArrayList<Object[]>();
		operandTypes64 = new ArrayList<Object[]>();
		encodings16 = new ArrayList<short[]>();
		encodings32 = new ArrayList<short[]>();
		encodings64 = new ArrayList<short[]>();
		descriptions16 = new ArrayList<String>();
		descriptions32 = new ArrayList<String>();
		descriptions64 = new ArrayList<String>();
		categories16 = new ArrayList<String[]>();
		categories32 = new ArrayList<String[]>();
		categories64 = new ArrayList<String[]>();
		minNumOperands = Integer.MAX_VALUE;
		maxNumOperands = 0;
	}

	public void addOperands(Object[] operands, short[] encoding16, short[] encoding32, short[] encoding64, String[] categories, String description) {
		if (encoding16!=null) {
			operandTypes16.add(operands);
			encodings16.add(encoding16);
			descriptions16.add(description);
			categories16.add(categories);
		}
		if (encoding32!=null) {
			operandTypes32.add(operands);
			encodings32.add(encoding32);
			descriptions32.add(description);
			categories32.add(categories);
		}
		if (encoding64!=null) {
			operandTypes64.add(operands);
			encodings64.add(encoding64);
			descriptions64.add(description);
			categories64.add(categories);
		}
		minNumOperands = Math.min(minNumOperands,operands.length);
		maxNumOperands = Math.max(maxNumOperands,operands.length);
	}

	public boolean isJumpInstruction() {
		String name = getName().toString();
		return (name.startsWith("j")) || (name.equals("ret")) || (name.equals("retf")) || (name.equals("retn")) || (name.equals("call")) || (name.equals("invoke")) || (name.equals("iret")) || (name.startsWith("loop")) || (name.startsWith("rep"));
	}

	/**
	 * @param languageScope the scope of the language containing this Mnemonic
	 * @return true iff the mnemonic is a prefix in the specified language scope (i.e. always exactly one operand that is also a Mnemonic)
	 */
	public boolean isPrefix(Scope languageScope) {
		return !categories32.isEmpty() && categories32.get(0).length>0 && categories32.get(0)[0]!=null && categories32.get(0)[0].startsWith("prefix");
	}

	public ArrayList<Object[]> getOperandTypes(int currentMode) {
		if (currentMode==64) {
			return operandTypes64;
		}
		if (currentMode==32) {
			return operandTypes32;
		}
		// currentMode==16
		return operandTypes16;
	}

	public ArrayList<short[]> getEncodings(int currentMode) {
		if (currentMode==64) {
			return encodings64;
		}
		if (currentMode==32) {
			return encodings32;
		}
		// currentMode==16
		return encodings16;
	}

	public ArrayList<String> getDescriptions(int currentMode) {
		if (currentMode==64) {
			return descriptions64;
		}
		if (currentMode==32) {
			return descriptions32;
		}
		// currentMode==16
		return descriptions16;
	}

	public int getMinNumOperands() {
		return minNumOperands;
	}

	public int getMaxNumOperands() {
		return maxNumOperands;
	}

	public ArrayList<String[]> getCategories(int currentMode) {
		if (currentMode==64) {
			return categories64;
		}
		if (currentMode==32) {
			return categories32;
		}
		// currentMode==16
		return categories16;
	}
}
